package com.shiguiwu.springboot3.gateway.sentinel;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: stone
 * @date: Created by 2023/12/16 14:34
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springboot3.gateway.sentinel
 */
//@Component
//@Order(Ordered.HIGHEST_PRECEDENCE)
public class SentinelFallbackHandler implements WebExceptionHandler {
    private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
        return webFluxResponseWriter(exchange.getResponse(), MediaType.APPLICATION_JSON_VALUE, HttpStatusCode.valueOf(200), "请求超过最大数，请稍候再试", -1);
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        }
        if (!BlockException.isBlockException(ex)) {
            return Mono.error(ex);
        }
        return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
    }

    private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
        return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
    }


    /**
     * 设置webflux模型响应
     * @param response    ServerHttpResponse
     * @param contentType content-type
     * @param status      http状态码
     * @param code        响应状态码
     * @param value       响应内容
     * @return Mono<Void>
     */
    public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatusCode status, Object value, int code) {
        //response.setStatusCode(status);
        //response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
        //
        //Map<String, Object> result = new HashMap<>();
        //result.put("code", code);
        //result.put("msg", value.toString());
        //DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
        //return response.writeWith(Mono.just(dataBuffer));
        HttpStatus httpStatus = HttpStatus.valueOf(status.value());
        response.setStatusCode(httpStatus);
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);

        Map<String, Object> result = new HashMap<>();
        result.put("code", code);
        result.put("msg", value.toString());
        DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
        return response.writeWith(Mono.just(dataBuffer));
    }
}
